use anyhow::Result;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};

use crate::config::Config;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TokenData {
    pub token: String,
    pub expires_at: u64,
}

static CACHED_TOKEN: Lazy<Mutex<Option<TokenData>>> = Lazy::new(|| Mutex::new(None));

pub async fn get_cached_copilot_token(config: &Config) -> Result<TokenData> {
    let current_time = SystemTime::now()
        .duration_since(UNIX_EPOCH)?
        .as_secs();

    {
        let cached = CACHED_TOKEN.lock();
        if let Some(token) = cached.as_ref() {
            if token.expires_at > current_time + 300 {
                return Ok(token.clone());
            }
        }
    }

    let new_token = refresh_token(config).await?;
    *CACHED_TOKEN.lock() = Some(new_token.clone());
    Ok(new_token)
}

async fn refresh_token(config: &Config) -> Result<TokenData> {
    let client = reqwest::Client::new();
    let response = client
        .get("https://api.github.com/copilot_internal/v2/token")
        .header("Authorization", format!("token {}", config.refresh_token))
        .header("editor-version", "vscode/1.96.1")
        .header("User-Agent", "vscode/1.96.1")
        .send()
        .await?;

    let status = response.status();
    if !status.is_success() {
        let error_text = response.text().await?;
        return Err(anyhow::anyhow!(
            "Failed to get token: {} - {}",
            status,
            error_text
        ));
    }

    let token_data = response.json::<TokenData>().await?;
    Ok(token_data)
} 